﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using BLToolkit.EditableObjects;
using BLToolkit.Reflection;


namespace LED_Editor.Model {
	[Serializable]
	public abstract class Frame : EditableObject<Frame> {
		static Frame() {
			Empty = TypeAccessor.CreateInstance<EmptyFrame>();
		}

		public Frame() {
		}

		public abstract int TrackId { get; set; }
		//public float FrameDuration
		//{
		//    get
		//    { return (float )((End - Start).TotalMinutes ); }
		//}
		private int _frameDuration;
		public virtual int FrameDuration {
			get {
				int duration = EndMarker - StartMarker;
				if (duration < 0) {
					//NotifyChanges = false;
					//EndMarker = StartMarker;
					//NotifyChanges = true;
					duration = 1;
				}

				_frameDuration = duration;
				return _frameDuration;
			}
			set {
				if (_frameDuration != value) {
					if (value < 1) {
						_frameDuration = 1;
					} else {
						_frameDuration = value;
					}
					NotifyChanges = false;
					EndMarker = StartMarker + _frameDuration;
					NotifyChanges = true;
					OnPropertyChanged("FrameDuration");
				}
			}
		}

		public float FrameDurationMilliseconds {
			get {
				return FrameDuration * 10;
			}
			set {
				FrameDuration = (int)((float)value / 10f);
			}
		}
		public float FrameDurationSeconds {
			get {
				return (float)Math.Round((double)FrameDuration / 100, 2);
			}
			set {
				FrameDuration = (int)(value * 100f);
			}
		}
		//private float _startMarker;
		//public float StartMarker
		//{
		//    get { return _startMarker; }
		//    set  {_startMarker = value; }
		//}
		//private float _endMarker;

		//public float EndMarker
		//{
		//    get { return _endMarker; }
		//    set { _endMarker = value; }
		//}

		public abstract int StartMarker { get; set; }
		public abstract int EndMarker { get; set; }


		//public abstract Color StartColor { get; set; }
		//public abstract Color EndColor { get; set; }
		private Color _startColor;
		public Color StartColor {
			get {
				if (_startColor.A == 0)
					return Color.Black;

				return _startColor;
			}
			set {
				if (_startColor.ToArgb() != value.ToArgb()) {
					base.OnPropertyChanged("StartColor");
					_startColor = value;
				}

			}
		}

		private Color _endColor;
		public Color EndColor {
			get {
				if (_endColor.A == 0)
					return Color.Black;

				return _endColor;
			}
			set {
				if (_endColor.ToArgb() != value.ToArgb()) {
					base.OnPropertyChanged("EndColor");
					_endColor = value;
				}
			}
		}



		public FrameStruct ToFrameStruct() {
			FrameStruct frame = new FrameStruct();
			frame.Duration = (ushort)FrameDuration;
			frame.StartColor = StartColor;
			frame.EndColor = EndColor;

			//frame.StartR  = StartColor.R  ;
			//frame.StartG = StartColor.G;
			//frame.StartB = StartColor.B;

			//frame.EndR = EndColor.R;
			//frame.EndG = EndColor.G;
			//frame.EndB = EndColor.B;

			return frame;
		}

		public static Frame GetSyncronizationFrame(int currentDuration, int maxDuration) {
			EmptyFrame lastSyncronizationFrame = EmptyFrame.CreateInstance();
			lastSyncronizationFrame.StartMarker = currentDuration;
			lastSyncronizationFrame.EndMarker = maxDuration;
			//lastSyncronizationFrame.FrameDuration = 0;

			lastSyncronizationFrame.StartColor = Color.FromArgb(0, 0, 0, 0);
			lastSyncronizationFrame.EndColor = Color.FromArgb(0, 0, 0, 0);

			return lastSyncronizationFrame;

		}

		public static EmptyFrame Empty;


	}

	[Serializable]
	public abstract class EmptyFrame : Frame {
		private int _frameDuration;

		public override int FrameDuration {
			get {
				int duration = EndMarker - StartMarker;
				if (duration < 0) {
					//NotifyChanges = false;
					//EndMarker = StartMarker;
					//NotifyChanges = true;
					duration = 0;
				}

				_frameDuration = duration;
				return _frameDuration;
			}
			set {
				if (_frameDuration != value) {
					if (value < 0) {
						_frameDuration = 0;
					} else {
						_frameDuration = value;
					}
					_frameDuration = value;
					NotifyChanges = false;
					EndMarker = StartMarker + _frameDuration;
					NotifyChanges = true;
					OnPropertyChanged("FrameDuration");
				}
			}
		}

		public static EmptyFrame CreateInstance() {
			return TypeAccessor.CreateInstance<EmptyFrame>();

		}
	}

	public struct FrameStruct {
		public ushort Duration { get; set; }
		public byte StartR { get { return StartColor.R; } set { StartColor = Color.FromArgb(value, StartColor.G, StartColor.B); } }
		public byte StartG { get { return StartColor.G; } set { StartColor = Color.FromArgb(StartColor.R, value, StartColor.B); } }
		public byte StartB { get { return StartColor.B; } set { StartColor = Color.FromArgb(StartColor.R, StartColor.G, value); } }
		public byte EndR { get { return EndColor.R; } set { EndColor = Color.FromArgb(value, EndColor.G, EndColor.B); } }
		public byte EndG { get { return EndColor.G; } set { EndColor = Color.FromArgb(EndColor.R, value, EndColor.B); } }
		public byte EndB { get { return EndColor.B; } set { EndColor = Color.FromArgb(EndColor.R, EndColor.G, value); } }

		public int StartMarker { get; set; }
		public int EndMarker { get; set; }

		public double DurationMilliseconds { get { return Duration * 10; } }


		private Color _startColor;
		public Color StartColor {
			get {
				//if (_startColor.R == 0 && _startColor.G == 0 && _startColor.B == 0)
				//{
				//    _startColor = Color.Empty;
				//}

				return _startColor;
			}
			set {
				_startColor = value;
			}
		}

		private Color _endColor;
		public Color EndColor {
			get {
				//if (_endColor.R == 0 && _endColor.G == 0 && _endColor.B == 0)
				//{
				//    _endColor = Color.Empty;
				//}
				return _endColor;
			}
			set {
				_endColor = value;

			}
		}

		public bool ColorsAreEmpty {
			get { return StartColor.ToArgb() == Color.Empty.ToArgb() && EndColor.ToArgb() == Color.Empty.ToArgb(); }
		}
		public bool ColorsAreEqual {
			get { return StartColor.ToArgb() == EndColor.ToArgb(); }
		}



		public static FrameStruct Empty;
		public override string ToString() {

			string startColorDescr = StartColor.IsNamedColor ? StartColor.Name : string.Format("[{0},{1},{2}]", StartR, StartG, StartB);
			string endColorDescr = EndColor.IsNamedColor ? EndColor.Name : string.Format("[{0},{1},{2}]", EndR, EndG, EndB);


			return string.Format("Кадр {0}ms, {1}->{2}", DurationMilliseconds, startColorDescr, endColorDescr);
		}

		//служебные
		public DateTime Start { get; set; }
		public DateTime End { get; set; }


		public byte[] ToByteArray() {
			byte[] bytes = BitConverter.GetBytes(Duration);
			if (bytes.Length != 2)
				throw new InvalidOperationException("Invalid bytes count");
			return new byte[] { 
                bytes[0] ,
                bytes[1] ,
                StartR ,
                StartG ,
                StartB ,
                EndR ,
                EndG ,
                EndB 
            };
		}

		public static int GetDuration(FrameStruct[] frames) {
			int duration = 0;
			foreach (FrameStruct item in frames)
				duration += item.Duration;
			return duration;
		}
	}
}
